package com.wondersgroup.fjzlpt.gateway.controller;

import com.netflix.zuul.context.RequestContext;
import com.wondersgroup.fjzlpt.gateway.filtes.exception.QuickZuulFilterException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * Created by lion on 2017/6/19.
 */
@Controller
@RequestMapping(value = "/error")
@EnableConfigurationProperties({ServerProperties.class})
public class QuickBasicErrorController implements ErrorController {

    protected final Log logger = LogFactory.getLog(getClass());

    private ErrorAttributes errorAttributes;

    @Autowired
    private ServerProperties serverProperties;

    /**
     * 初始化ExceptionController
     * @param errorAttributes
     */
    @Autowired
    public QuickBasicErrorController(ErrorAttributes errorAttributes) {
        Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
        this.errorAttributes = errorAttributes;
    }

    @RequestMapping("/404.html")
    public String busniess404(HttpServletRequest request,
                        HttpServletResponse response){
        return "404/404";
    }

    @RequestMapping("/500.html")
    public String busniess500(HttpServletRequest request,
                              HttpServletResponse response){
        return "500/500";
    }

    @RequestMapping(produces = {"text/html", "application/x-ms-application"})
    public String errorHtml(HttpServletRequest request,
                                  HttpServletResponse response) throws IOException {
        response.setStatus(HttpStatus.OK.value());
        RequestContext ctx = RequestContext.getCurrentContext();
        Exception e = (Exception)ctx.get("throwable");
        e = (Exception)ExceptionUtils.getRootCause(e);
        Map<String, Object> requestErrorAttr = getErrorAttributes(request);
        /*定义错误信息*/
        HttpStatus status = getHttpStatus(requestErrorAttr);
        String error = (String)requestErrorAttr.get("error");
        String exp = (String)requestErrorAttr.get("exception");
        String executedFilters = "";
        String message = ExceptionUtils.getRootCauseMessage(e);

        StringBuilder sbud = (StringBuilder)ctx.get("executedFilters");
        if(sbud != null){
            executedFilters = sbud.toString();
        }

        request.setAttribute("status", status.value()+":"+status.getReasonPhrase());
        request.setAttribute("error", error);
        request.setAttribute("exception", exp);
        request.setAttribute("message", message);
        request.setAttribute("executedFilters", executedFilters);
        /*自定义异常*/
        if(e instanceof QuickZuulFilterException){
            QuickZuulFilterException qe = (QuickZuulFilterException)e;
            return handlerQuickZuulFilterException(ctx, request, qe);
        }else{
            return "error/errorHtml";
        }
    }

    @RequestMapping(produces = "application/json")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> errorJson(HttpServletRequest request, HttpServletResponse response){
        Map<String, Object> requestErrorAttr = getErrorAttributes(request);
        RequestContext ctx = RequestContext.getCurrentContext();
        Exception e = (Exception)ctx.get("throwable");
        String message = ExceptionUtils.getRootCauseMessage(e);
        requestErrorAttr.put("message", message);
        requestErrorAttr.remove("trace");
        HttpStatus status = getHttpStatus(requestErrorAttr);
        return new ResponseEntity(requestErrorAttr, HttpStatus.UNAUTHORIZED);
    }

    /**
     * 处理自定义异常
     * @param ctx
     * @param request
     * @return
     */
    private String handlerQuickZuulFilterException(RequestContext ctx, HttpServletRequest request, QuickZuulFilterException qe){
        String uri = "error/fail";
        String type = qe.getType();
        if(QuickZuulFilterException.TYPE_UNAUTH.equals(type)){
            uri = "error/unAuth";
        }else if(QuickZuulFilterException.TYPE_CERT_TIME_OUT.equals(type)){
            uri = "error/certTimeout";
        }
        return uri;
    }

    private HttpStatus getHttpStatus(Map<String, Object> requestErrorAttr) {
        return HttpStatus.valueOf((Integer)requestErrorAttr.get("status"));
    }

    private Map<String, Object> getErrorAttributes(HttpServletRequest request){
        RequestAttributes requestAttributes = new ServletRequestAttributes(request);
        return this.errorAttributes.getErrorAttributes(requestAttributes, true);
    }

    @Override
    public String getErrorPath() {
        return this.serverProperties.getError().getPath();
    }
}
